package org.liaohailong.library.widget

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.util.SparseArray
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.LinearLayout
import androidx.annotation.ColorInt
import org.liaohailong.library.R

/**
 * Author: liaohailong
 * Date: 2020/7/25
 * Time: 9:47
 * Description: 仿美团-外卖模块，底部点击弹性导航栏
 **/
class MTNavigationLayout(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
    LinearLayout(context, attrs, defStyleAttr) {
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context) : this(context, null)

    private fun log(msg: String) {
        Log.i("MTNavigationLayout", msg)
    }

    /**
     * 边线颜色，位于内容背景之上，跟随动画变动
     */
    @ColorInt
    private var defaultLineColor: Int = Color.parseColor("#80000000")

    /**
     * 内容背景色
     */
    @ColorInt
    private var defaultContentBgColor: Int = Color.WHITE

    // 边线画笔
    private val linePaint: Paint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 1f
        color = defaultLineColor
        isAntiAlias = true
    }

    // child view 内容画笔
    private val contentBgPaint: Paint = Paint().apply {
        style = Paint.Style.FILL_AND_STROKE
        color = defaultContentBgColor
        isAntiAlias = true
    }

    // item信息缓存池
    private val itemPool = SparseArray<NavigationItem>()

    // 背景显示区域
    private val backgroundRect = Rect()

    // 布局上边线
    private val linePath = Path()

    // 当前选中的位置
    private var selectedIndex = -1

    init {
        val a = context.obtainStyledAttributes(attrs, R.styleable.MTNavigationLayout)
        val lineColor = a.getColor(R.styleable.MTNavigationLayout_lineColor, defaultLineColor)
        val contentBgColor =
            a.getColor(R.styleable.MTNavigationLayout_contentBackgroundColor, defaultContentBgColor)

        setLineColor(lineColor)
        setContentBackgroundColor(contentBgColor)

        a.recycle()


        // 执行动画需要让子视图内容向上平移
        clipChildren = false
        clipToPadding = false
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        log("onFinishInflate")
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        log("onAttachedToWindow")
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        log("onVisibilityChanged")
    }

    override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
        super.onWindowFocusChanged(hasWindowFocus)
        log("onWindowFocusChanged")
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        log("onMeasure")
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        log("onSizeChanged")
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        log("onLayout")
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        log("onDraw")
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        log("onDetachedFromWindow")
    }

    /**
     * 设置边线颜色
     */
    fun setLineColor(@ColorInt color: Int) {
        linePaint.color = color
        invalidate()
    }

    /**
     * 设置内容背景色
     */
    fun setContentBackgroundColor(@ColorInt color: Int) {
        contentBgPaint.color = color
        invalidate()
    }


    private fun getItemInfoByIndex(index: Int): NavigationItem {
        var itemInfo = itemPool.get(index)
        if (itemInfo == null) {
            itemInfo = NavigationItem()
            itemPool.put(index, itemInfo)
        }
        return itemInfo
    }

    override fun dispatchDraw(canvas: Canvas?) {
        // 1，计算所有子视图位置，控制点
        prepareItemInfo()

        // 2，计算背景顶部边线path
        preparePath()

        // 背景底色+边线
        canvas?.apply {
            // 绘制底色
            drawPath(linePath, contentBgPaint)

            // 绘制边线
            drawPath(linePath, linePaint)
        }

        // 绘制linear-layout子视图内容
        super.dispatchDraw(canvas)
    }

    private fun prepareItemInfo() {
        if (childCount < 1) return

        // 布局child完毕，获取具体child的尺寸和位置
        for (i in 0 until childCount) {
            val itemInfo = getItemInfoByIndex(i)
            val childView = getChildAt(i)
            val x = childView.x
            val y = childView.y
            val measuredWidth = childView.measuredWidth
            val left = x.toInt();
            val top = y.toInt();
            val right = left + measuredWidth
            val centerX = left + ((right - left) / 2)

            itemInfo.leftPoint.set(left, top)
            itemInfo.centerPoint.set(centerX, top)
            itemInfo.rightPoint.set(right, top)
        }
        // 获取背景显示区域尺寸
        val selfLeft = 0 + paddingLeft
        val selfTop = 0 + paddingTop
        val selfRight = selfLeft + measuredWidth - paddingRight
        val selfBottom = selfTop + measuredHeight - paddingBottom
        backgroundRect.set(selfLeft, selfTop, selfRight, selfBottom)
    }

    private fun preparePath() {
        if (childCount < 1) return

        // 绘制背景内容
        // 绘制线性布局矩形框
        linePath.reset()
        // 左上起点
        linePath.moveTo(backgroundRect.left.toFloat(), backgroundRect.top.toFloat())

        // 连接child item坐标
        for (i in 0 until childCount) {
            val itemInfo = getItemInfoByIndex(i)

            val leftX = itemInfo.leftPoint.x.toFloat()
            val leftY = itemInfo.leftPoint.y.toFloat()

            val centerX = itemInfo.centerPoint.x.toFloat()
            val centerY = itemInfo.centerPoint.y.toFloat() - itemInfo.offset

            val rightX = itemInfo.rightPoint.x.toFloat()
            val rightY = itemInfo.rightPoint.y.toFloat()

            val totalLength = rightX - leftX

            val x1 = leftX + (totalLength / 2) * 2 / 4
            val y1 = leftY

            val x2 = leftX + (totalLength / 2) * 3 / 4
            val y2 = centerY

            val x3 = centerX
            val y3 = centerY

            val x4 = centerX + (totalLength / 2) * 1 / 4
            val y4 = centerY

            val x5 = centerX + (totalLength / 2) * 2 / 4
            val y5 = rightY

            val x6 = rightX
            val y6 = rightY

            linePath.lineTo(leftX, leftY)
            linePath.cubicTo(x1, y1, x2, y2, x3, y3)
            linePath.cubicTo(x4, y4, x5, y5, x6, y6)
        }

        linePath.lineTo(backgroundRect.right.toFloat(), backgroundRect.top.toFloat())
        linePath.lineTo(backgroundRect.right.toFloat(), backgroundRect.bottom.toFloat())
        linePath.lineTo(backgroundRect.left.toFloat(), backgroundRect.bottom.toFloat())
        linePath.close()
    }

    private fun getAnimOffsetValue() = paddingTop / 2
    private var animator: ValueAnimator? = null

    /**
     * @return true表示本次点击成功生效，false表示点击无效，防止执行动画过程中快速点击
     */
    fun select(index: Int, callback: AnimCallback?): Boolean {
        if (childCount - 1 < index) return false
        if (animator != null) return false
        if (selectedIndex == index) return false
        selectedIndex = index

        // 开启动画
        val maxOffset = getAnimOffsetValue()
        animator = ValueAnimator.ofFloat(0.0f, 1.5f, 1.0f).apply {
            duration = 400
            interpolator = AccelerateDecelerateInterpolator()
            addUpdateListener {
                val progress = it.animatedValue as Float

                for (i in 0 until childCount) {
                    val itemInfo = getItemInfoByIndex(i)
                    val yOffset = if (i == selectedIndex) {
                        progress * maxOffset
                    } else {
                        var rProgress = 1.0f - progress
                        rProgress = 0.0f.coerceAtLeast(rProgress)
                        (rProgress) * itemInfo.offset
                    }
                    itemInfo.offset = yOffset.toInt()

                    invalidate()

                    callback?.onAnimProgress(i, progress, yOffset.toInt())
                }
            }
            addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator?) {
                    animator?.apply {
                        removeAllUpdateListeners()
                        removeAllListeners()
                    }
                    animator = null
                }
            })
        }

        animator?.start()
        return true
    }

    internal class NavigationItem {
        var leftPoint = Point()
        var rightPoint = Point()
        var centerPoint = Point()
        var offset = 0
    }

    interface AnimCallback {
        /**
         * @param index 当前执行动画的item 下标
         * @param progress [0.0f~1.0f]
         * @param offsetValue 偏移值
         */
        fun onAnimProgress(index: Int, progress: Float, offsetValue: Int)
    }
}